Q1
First I load the data files
Next I reshape dat into the handful data format. I use tidyr package for the aim instead of reshape package because the foramer is the improved version of the latter.
install.packages('tidyverse')
URL 'https://cran.rstudio.com/bin/macosx/mavericks/contrib/3.3/tidyverse_1.1.1.tgz' を試しています
Content type 'application/x-gzip' length 37228 bytes (36 KB)
==================================================
downloaded 36 KB
The downloaded binary packages are in
/var/folders/1w/nyst5xl16t329h4gpz0j49hm0000gn/T//Rtmp2exVAC/downloaded_packages
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ----------------------------------------------------------------------------------------------------------------------------------
filter(): dplyr, stats
lag(): dplyr, stats
dat <- dat %>%
tidyr::gather(key=From, value=value, Alabama,Alaska,Arizona,Arkansas,California,Colorado,Connecticut,Delaware,District\ of\ Columbia,Florida,Georgia,Hawaii,Idaho,Illinois,Indiana,Iowa,Kansas,Kentucky,Louisiana,Maine,Maryland,Massachusetts,Michigan,Minnesota,Mississippi,Missouri,Montana,Nebraska,Nevada,New\ Hampshire,New\ Jersey,New\ Mexico,New\ York,North\ Carolina,North\ Dakota,Ohio,Oklahoma,Oregon,Pennsylvania,Rhode\ Island,South\ Carolina,South\ Dakota,Tennessee,Texas,Utah,Vermont,Virginia,Washington,West\ Virginia,Wisconsin,Wyoming)
エラー: 想定外の入力です in:
"dat <- dat %>%
tidyr::gather(key=From, value=value, Alabama,Alaska,Arizona,Arkansas,California,Colorado,Connecticut,Delaware,District\"
Delete the puctuations.
Then I add two new columns to the above data frame.
d1 <- merge(dat, states, by.x="From", by.y="States")
d1 <- d1[,c(-5,-6)]
names(d1)[4] <- "ID_From"
d2 <- merge(d1, states, by.x="To", by.y="States")
d2 <- d2[,c(-6,-7)]
names(d2)[5] <- "ID_To"
dat <- d2
dat
Sort the data frame in the ascending order
dat <- arrange(dat, ID_From)
dat <- arrange(dat, ID_To)
dat
Convert the above data frame into the matrix form
Drawing the chord diagram
chorddiag(as.matrix(t5),groupColors=states$Color,showTicks=F,groupnamePadding = 20,groupThickness=.05,groupnameFontsize=10)
row names of the 'data' matrix differ from its column names or the 'groupNames' argument.
Q2
Read “Stops On Lines” and the all GIS data of bus lines.
library(dplyr)
library(sp)
library(rgdal)
library(leaflet)
library(ggmap)
# Bus Stops
SOL <- readOGR("/Users/susu/Desktop/Hong\ Kong/Semester2/Big_Data/assignment_data/as1/BusStops1216","StopsOnLines1216")
SOL.pj <- spTransform(SOL, CRS("+proj=longlat +datum=WGS84"))
# Bus Routes
CC <- readOGR("/Users/susu/Desktop/Hong\ Kong/Semester2/Big_Data/assignment_data/as1/ComCir1216","ComCir1216")
CC.pj <- spTransform(CC, CRS("+proj=longlat +datum=WGS84"))
LE <- readOGR("/Users/susu/Desktop/Hong\ Kong/Semester2/Big_Data/assignment_data/as1/LimExp1216","LimExp1216")
LE.pj <- spTransform(LE, CRS("+proj=longlat +datum=WGS84"))
LCBD <- readOGR("/Users/susu/Desktop/Hong\ Kong/Semester2/Big_Data/assignment_data/as1/LocalCBD1216","LocalCBD1216")
LCBD.pj <- spTransform(LCBD, CRS("+proj=longlat +datum=WGS84"))
LNCBD <- readOGR("/Users/susu/Desktop/Hong\ Kong/Semester2/Big_Data/assignment_data/as1/LocalNonCBD1216","LocalNonCBD1216")
LNCBD.pj <- spTransform(LNCBD, CRS("+proj=longlat +datum=WGS84"))
RBRT <- readOGR("/Users/susu/Desktop/Hong\ Kong/Semester2/Big_Data/assignment_data/as1/RapidBRT1216","RapidBRT1216")
RBRT.pj <- spTransform(RBRT, CRS("+proj=longlat +datum=WGS84"))
make Line_list
Line_list <- list()
for (i in 1:6){
for (j in 1:length(tmps[[i]])){
Line_list <- c(Line_list, tmps[[i]][j]@lines[[1]]@Lines)
}
}
エラー: スロット "lines"を、スロットを持たない基本クラス ("list") のオブジェクトから得ようとしました
make new_id
pjs <- list(CC.pj, LE.pj, LCBD.pj, LNCBD.pj, RBRT.pj)
LinLSs <- list()
for (i in 1:5){
LinLSs <- c(LinLSs, sapply(pjs[[i]]@lines, function(x) length(x@Lines)))
}
LinLSs <- LinLSs %>% unlist()
new_id <- sapply(1:length(LinLSs), function(x) paste0(x, "_", seq.int(LinLSs[[x]]))) %>%
unlist()
SLDF <- mapply(function(x, y) Lines(x, ID = y), x = Line_list, y = new_id) %>%
list() %>%
SpatialLines() %>%
SpatialLinesDataFrame(data = DAT)
SpatialLines(.) でエラー:
lines list not exclusively filled with Lines objects
make new lines and LA map
Q3
First I load the data.
library(quantmod)
library(highcharter)
x <- getSymbols("AUD/JPY", src = "oanda", auto.assign = FALSE)
y <- getSymbols("GBP/USD", src = "oanda", auto.assign = FALSE)
Next make Bollinger’s bands for each exchange rate.
x.BBands.ll <- BBands(x)$dn
x.BBands.ul <- BBands(x)$up
x.BBands.m <- BBands(x)$mavg
y.BBands.ll <- BBands(y)$dn
y.BBands.ul <- BBands(y)$up
y.BBands.m <- BBands(y)$mavg
The drawing code is as follows.
hc <- highchart(type="stock") %>%
hc_title(text="Charting Exchange Rates") %>%
hc_subtitle(text = "Data extracted using quantmod package") %>%
hc_yAxis_multiples(
list(top = "0%", height = "50%", offset=0, opposite=TRUE),
list(top = "50%", height = "50%", offset=0, opposite=TRUE)
)%>%
hc_add_series(x, id = "audjpy",name ="audjpy", yAxis=0, color="blue", lineWidth=1.5) %>%
hc_add_series(x.BBands.ll, id = "audjpy.ll", name="audjpy Lower BBands",yAxis=0,
color="black",dashStyle='shortdash', lineWidth=1) %>%
hc_add_series(x.BBands.ul, id = "audjpy.ul", name="audjpy Upper BBands",yAxis=0,
color="black",lineWidth=1) %>%
hc_add_series(x.BBands.m, id = "audjpy.m",name="audjpy BBands MA", yAxis=0,
color="red",lineWidth=1) %>%
hc_add_series(y, id = "gbpusd",name="gbpusd",yAxis=1, color="green", lineWidth=1.5) %>%
hc_add_series(y.BBands.ll, id = "gbpusd.ll",name="gbpusd Lower BBands", yAxis=1,
color="black",dashStyle='shortdash',lineWidth=1) %>%
hc_add_series(y.BBands.ul, id = "gbpusd.ul",name="gbpusd Upper BBands", yAxis=1,
color="black",lineWidth=1) %>%
hc_add_series(y.BBands.m, id = "gbpusd.m",name="gbpusd BBands MA", yAxis=1,
color="red",lineWidth=1) %>%
hc_add_theme(hc_theme_538())
hc
Q4
Load libraries and check the raw data. And make ffdf after converting character columns to factor columns in original df.
library(nycflights13)
library(ffbase)
library(ffbase2)
library(biglm)
library(pROC)
library(chron)
tmp <- flights
tmp$carrier <- as.factor(tmp$carrier)
tmp$tailnum <- as.factor(tmp$tailnum)
tmp$origin <- as.factor(tmp$origin)
tmp$dest <- as.factor(tmp$dest)
flightff <- as.ffdf(tmp)
Next I make new columns as follows
flightff$Delay <- ffifelse(flightff$dep_delay > 0 | flightff$dep_delay == 0 , 1,0)
flightff$DepHour <- flightff$hour
flightff$Car <- ffifelse(flightff$carrier %in% as.factor(c("DL","US","DH","UA")), 1, 0)
flightff$Night <- ffifelse(flightff$hour > 18 | flightff$hour < 6, 1, 0)
flightff$Weekend <- ffifelse(day.of.week(month=flightff$month, day=flightff$day, year=flightff$year) == 6, 1, 0)
I exclude the rows whose Delay values are NA and rename it to logitff. And then I split the dataset into train set and test set.
logitff <- flightff[!is.na(flightff$Delay),]
indx <- ff(1:nrow(logitff))
p <- 0.7
trainIndx <- ff(indx[1:trunc(length(indx)*p)])
trainset <- logitff[trainIndx,]
testIndx <- ff(indx[(trunc(length(indx)*p)+1):length(indx)])
testset <- logitff[testIndx,]
Logistic regression
fit <- bigglm.ffdf(Delay~DepHour+Car+Night+Weekend, data = trainset, family=binomial(), sandwich=TRUE)
summary(fit)
Large data regression model: bigglm(Delay ~ DepHour + Car + Night + Weekend, data = trainset,
family = binomial(), sandwich = TRUE)
Sample size = 229964
Coef (95% CI) SE p
(Intercept) -1.5418 -1.5731 -1.5104 0.0157 0
DepHour 0.1020 0.0996 0.1044 0.0012 0
Car -0.0680 -0.0858 -0.0503 0.0089 0
Night -0.2619 -0.2912 -0.2326 0.0147 0
Weekend -0.1543 -0.1821 -0.1265 0.0139 0
Sandwich (model-robust) standard errors
predict and make confusionmatrix in train_set
train_pred <- predict(fit, newdata = trainset, type="response")
train_pred <- ifelse(train_pred>0.5, 1,0)
train_confusion <- table(as.integer(as.data.frame(trainset)$Delay), as.integer(train_pred))
train_confusion <- addmargins(train_confusion)
train_confusion
0 1 Sum
0 94128 36392 130520
1 56845 42599 99444
Sum 150973 78991 229964
predict and make confusionmatrix in test_set
test_pred <- predict(fit, newdata = testset, type="response")
test_pred <- ifelse(test_pred>0.5, 1,0)
test_confusion <- table(as.integer(as.data.frame(testset)$Delay), as.integer(test_pred))
test_confusion <- addmargins(test_confusion)
test_confusion
0 1 Sum
0 39997 13058 53055
1 25558 19944 45502
Sum 65555 33002 98557
Draw ROC curve
test_pred <- predict(fit, newdata = testset, type="response")
roc <- roc(as.integer(as.data.frame(testset)$Delay), as.numeric(test_pred))
plot(roc)

Q5
First I load the data. And before using spark I delete the irrelevant columns.
Remove the observations satisfying the condition
Split this data into trainset and testset.
test
$test
NA
Use Decision tree
decision_tree <- train %>%
ml_decision_tree(response="BOROUGH", features = c("LATITUDE","LONGITUDE"), max.bins = 200L, max.depth = 10L, seed=123L) %>%
Prediction
table(pred$BOROUGH, pred$prediction)
0 1 2 3 4
BRONX 0 0 0 8876 0
BROOKLYN 21181 0 24 0 1
MANHATTAN 0 17944 0 0 0
QUEENS 25 1 17777 0 0
STATEN ISLAND 23 0 0 0 3169
LS0tCnRpdGxlOiAiQmlnIERhdGEgQW5hbHl0aWNzIEFzc2lnbm1lbnQgMSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgUTEKCkZpcnN0IEkgbG9hZCB0aGUgZGF0YSBmaWxlcwpgYGB7cn0KZGF0IDwtIHJlYWQuY3N2KCIvVXNlcnMvc3VzdS9EZXNrdG9wL0hvbmdcIEtvbmcvU2VtZXN0ZXIyL0JpZ19EYXRhL2Fzc2lnbm1lbnRfZGF0YS9hczEvbWlncmF0aW9uMjAxMi5jc3YiKQpoZWFkKGRhdCkKYGBgCgpgYGB7cn0Kc3RhdGVzIDwtIHJlYWQuY3N2KCIvVXNlcnMvc3VzdS9EZXNrdG9wL0hvbmdcIEtvbmcvU2VtZXN0ZXIyL0JpZ19EYXRhL2Fzc2lnbm1lbnRfZGF0YS9hczEvc3RhdGVzX2Nob3JkLmNzdiIpCnN0YXRlcwpgYGAKCk5leHQgSSByZXNoYXBlIGRhdCBpbnRvIHRoZSBoYW5kZnVsIGRhdGEgZm9ybWF0LiBJIHVzZSAqKnRpZHlyIHBhY2thZ2UqKiBmb3IgdGhlIGFpbSBpbnN0ZWFkIG9mICoqcmVzaGFwZSBwYWNrYWdlKiogYmVjYXVzZSB0aGUgZm9yYW1lciBpcyB0aGUgaW1wcm92ZWQgdmVyc2lvbiBvZiB0aGUgbGF0dGVyLgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoJ3RpZHl2ZXJzZScpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCmBgYHtyfQpkYXQgPC0gZGF0ICU+JQp0aWR5cjo6Z2F0aGVyKGtleT1Gcm9tLCB2YWx1ZT12YWx1ZSwgQWxhYmFtYSxBbGFza2EsQXJpem9uYSxBcmthbnNhcyxDYWxpZm9ybmlhLENvbG9yYWRvLENvbm5lY3RpY3V0LERlbGF3YXJlLERpc3RyaWN0Lm9mLkNvbHVtYmlhLEZsb3JpZGEsR2VvcmdpYSxIYXdhaWksSWRhaG8sSWxsaW5vaXMsSW5kaWFuYSxJb3dhLEthbnNhcyxLZW50dWNreSxMb3Vpc2lhbmEsTWFpbmUsTWFyeWxhbmQsTWFzc2FjaHVzZXR0cyxNaWNoaWdhbixNaW5uZXNvdGEsTWlzc2lzc2lwcGksTWlzc291cmksTW9udGFuYSxOZWJyYXNrYSxOZXZhZGEsTmV3LkhhbXBzaGlyZSxOZXcuSmVyc2V5LE5ldy5NZXhpY28sTmV3LllvcmssTm9ydGguQ2Fyb2xpbmEsTm9ydGguRGFrb3RhLE9oaW8sT2tsYWhvbWEsT3JlZ29uLFBlbm5zeWx2YW5pYSxSaG9kZS5Jc2xhbmQsU291dGguQ2Fyb2xpbmEsU291dGguRGFrb3RhLFRlbm5lc3NlZSxUZXhhcyxVdGFoLFZlcm1vbnQsVmlyZ2luaWEsV2FzaGluZ3RvbixXZXN0LlZpcmdpbmlhLFdpc2NvbnNpbixXeW9taW5nKQpgYGAKCkRlbGV0ZSB0aGUgcHVjdHVhdGlvbnMuCgpgYGB7cn0KZGF0IDwtIGRhdGEuZnJhbWUoYXBwbHkoZGF0LCAyLCBmdW5jdGlvbih5KSBnc3ViKCJbWzpwdW5jdDpdXSIsICIgIiwgeSkpKQpkYXQKYGBgCgpUaGVuIEkgYWRkIHR3byBuZXcgY29sdW1ucyB0byB0aGUgYWJvdmUgZGF0YSBmcmFtZS4KCmBgYHtyfQpkMSA8LSBtZXJnZShkYXQsIHN0YXRlcywgYnkueD0iRnJvbSIsIGJ5Lnk9IlN0YXRlcyIpCmQxIDwtIGQxWyxjKC01LC02KV0KbmFtZXMoZDEpWzRdIDwtICJJRF9Gcm9tIgoKZDIgPC0gbWVyZ2UoZDEsIHN0YXRlcywgYnkueD0iVG8iLCBieS55PSJTdGF0ZXMiKQpkMiA8LSBkMlssYygtNiwtNyldCm5hbWVzKGQyKVs1XSA8LSAiSURfVG8iCmRhdCA8LSBkMgpkYXQKYGBgCgpTb3J0IHRoZSBkYXRhIGZyYW1lIGluIHRoZSBhc2NlbmRpbmcgb3JkZXIKCmBgYHtyfQpkYXQgPC0gYXJyYW5nZShkYXQsIElEX0Zyb20pCmRhdCA8LSBhcnJhbmdlKGRhdCwgSURfVG8pCmRhdApgYGAKCkNvbnZlcnQgdGhlIGFib3ZlIGRhdGEgZnJhbWUgaW50byB0aGUgbWF0cml4IGZvcm0KCmBgYHtyfQp0MSA8LSBkYXRbLGMoMSwyLDQsNSldCnQxIDwtIHQxICU+JQogIHNwcmVhZChrZXk9VG8sIHZhbHVlPUlEX1RvKQoKdDIgPC0gZGF0WyxjKDEsMiwzLDQpXQp0MiA8LSB0MiAlPiUKICBzcHJlYWQoa2V5PVRvLCB2YWx1ZT12YWx1ZSkKCnQzIDwtIHJiaW5kKHQxWzEsXSx0MikKdDMkRnJvbSA8LSBhcy5jaGFyYWN0ZXIodDMkRnJvbSkKdDNbMSwyXSA8LSAwCnQzWzEsMV0gPC0gIklEX1RvIgp0MyA8LSB0MyAlPiUKICBhcnJhbmdlKElEX0Zyb20pCgpsaWJyYXJ5KGRhdGEudGFibGUpCnNldGNvbG9yZGVyKHQzLGMoIkZyb20iLCJJRF9Gcm9tIiwiQ29ubmVjdGljdXQiLCJNYWluZSIsIk1hc3NhY2h1c2V0dHMiLCJOZXcgSGFtcHNoaXJlIiwiUmhvZGUgSXNsYW5kIiwKIlZlcm1vbnQiLCJOZXcgSmVyc2V5IiwiTmV3IFlvcmsiLCJQZW5uc3lsdmFuaWEiLCJJbGxpbm9pcyIsIkluZGlhbmEiLAoiTWljaGlnYW4iLCJPaGlvIiwiV2lzY29uc2luIiwiSW93YSIsIkthbnNhcyIsIk1pbm5lc290YSIsCiJNaXNzb3VyaSIsIk5lYnJhc2thIiwiTm9ydGggRGFrb3RhIiwiU291dGggRGFrb3RhIiwiRGVsYXdhcmUiLCJGbG9yaWRhIiwKIkdlb3JnaWEiLCJNYXJ5bGFuZCIsIk5vcnRoIENhcm9saW5hIiwiU291dGggQ2Fyb2xpbmEiLCJWaXJnaW5pYSIsIkRpc3RyaWN0IG9mIENvbHVtYmlhIiwKIldlc3QgVmlyZ2luaWEiLCJBbGFiYW1hIiwiS2VudHVja3kiLCJNaXNzaXNzaXBwaSIsIlRlbm5lc3NlZSIsIkFya2Fuc2FzIiwKIkxvdWlzaWFuYSIsIk9rbGFob21hIiwiVGV4YXMiLCJBcml6b25hIiwiQ29sb3JhZG8iLCJJZGFobyIsCiJNb250YW5hIiwiTmV2YWRhIiwiTmV3IE1leGljbyIsIlV0YWgiLCJXeW9taW5nIiwiQWxhc2thIiwKIkNhbGlmb3JuaWEiLCJIYXdhaWkiLCJPcmVnb24iLCJXYXNoaW5ndG9uIikpCgp0MyA8LSB0M1tjKC0xKSxjKC0yKV0KCnQ0IDwtIHQzWywtMV0Kcm93bmFtZXModDQpIDwtIHQzWywxXQoKdDUgPC0gZGF0YS5mcmFtZShhcHBseSh0NCwgMiwgZnVuY3Rpb24oeSkgYXMubnVtZXJpYyh5KSkpCnJvd25hbWVzKHQ1KSA8LSB0M1ssMV0KdDUKYGBgCgpEcmF3aW5nIHRoZSBjaG9yZCBkaWFncmFtCmBgYHtyfQpsaWJyYXJ5KGNob3JkZGlhZykKCmNob3JkZGlhZyhhcy5tYXRyaXgodDUpLGdyb3VwQ29sb3JzPXN0YXRlcyRDb2xvcixzaG93VGlja3M9Rixncm91cG5hbWVQYWRkaW5nPTIwLGdyb3VwVGhpY2tuZXNzPS4wNSxncm91cG5hbWVGb250c2l6ZT0xMCkKYGBgCgoKIyMgUTIKClJlYWQgIlN0b3BzIE9uIExpbmVzIiBhbmQgdGhlIGFsbCBHSVMgZGF0YSBvZiBidXMgbGluZXMuCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNwKQpsaWJyYXJ5KHJnZGFsKQpsaWJyYXJ5KGxlYWZsZXQpCmxpYnJhcnkoZ2dtYXApCgojIEJ1cyBTdG9wcwpTT0wgPC0gcmVhZE9HUigiL1VzZXJzL3N1c3UvRGVza3RvcC9Ib25nXCBLb25nL1NlbWVzdGVyMi9CaWdfRGF0YS9hc3NpZ25tZW50X2RhdGEvYXMxL0J1c1N0b3BzMTIxNiIsIlN0b3BzT25MaW5lczEyMTYiKQpTT0wucGogPC0gc3BUcmFuc2Zvcm0oU09MLCBDUlMoIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikpCgojIEJ1cyBSb3V0ZXMKQ0MgPC0gcmVhZE9HUigiL1VzZXJzL3N1c3UvRGVza3RvcC9Ib25nXCBLb25nL1NlbWVzdGVyMi9CaWdfRGF0YS9hc3NpZ25tZW50X2RhdGEvYXMxL0NvbUNpcjEyMTYiLCJDb21DaXIxMjE2IikKQ0MucGogPC0gc3BUcmFuc2Zvcm0oQ0MsIENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSkKTEUgPC0gcmVhZE9HUigiL1VzZXJzL3N1c3UvRGVza3RvcC9Ib25nXCBLb25nL1NlbWVzdGVyMi9CaWdfRGF0YS9hc3NpZ25tZW50X2RhdGEvYXMxL0xpbUV4cDEyMTYiLCJMaW1FeHAxMjE2IikKTEUucGogPC0gc3BUcmFuc2Zvcm0oTEUsIENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSkKTENCRCA8LSByZWFkT0dSKCIvVXNlcnMvc3VzdS9EZXNrdG9wL0hvbmdcIEtvbmcvU2VtZXN0ZXIyL0JpZ19EYXRhL2Fzc2lnbm1lbnRfZGF0YS9hczEvTG9jYWxDQkQxMjE2IiwiTG9jYWxDQkQxMjE2IikKTENCRC5waiA8LSBzcFRyYW5zZm9ybShMQ0JELCBDUlMoIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikpCkxOQ0JEIDwtIHJlYWRPR1IoIi9Vc2Vycy9zdXN1L0Rlc2t0b3AvSG9uZ1wgS29uZy9TZW1lc3RlcjIvQmlnX0RhdGEvYXNzaWdubWVudF9kYXRhL2FzMS9Mb2NhbE5vbkNCRDEyMTYiLCJMb2NhbE5vbkNCRDEyMTYiKQpMTkNCRC5waiA8LSBzcFRyYW5zZm9ybShMTkNCRCwgQ1JTKCIrcHJvaj1sb25nbGF0ICtkYXR1bT1XR1M4NCIpKQpSQlJUIDwtIHJlYWRPR1IoIi9Vc2Vycy9zdXN1L0Rlc2t0b3AvSG9uZ1wgS29uZy9TZW1lc3RlcjIvQmlnX0RhdGEvYXNzaWdubWVudF9kYXRhL2FzMS9SYXBpZEJSVDEyMTYiLCJSYXBpZEJSVDEyMTYiKQpSQlJULnBqIDwtIHNwVHJhbnNmb3JtKFJCUlQsIENSUygiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQiKSkKYGBgCgptYWtlIExpbmVfbGlzdApgYGB7cn0KIyBJbmRpdmlkdWFsIEJ1cyBSb3V0ZQpJTkQucGogPC0gbGlzdCgpCmxheWVyX2xpc3QgPC0gb2dyTGlzdExheWVycygiL1VzZXJzL3N1c3UvRGVza3RvcC9Ib25nXCBLb25nL1NlbWVzdGVyMi9CaWdfRGF0YS9hc3NpZ25tZW50X2RhdGEvYXMxL0luZGl2aWR1YWxzMTIxNiIpCmZvciAoaSBpbiBsYXllcl9saXN0KXsKICBpZiAoaSAhPSA3MjgpewogICAgSU5ELnBqIDwtIGMoSU5ELnBqLCBzcFRyYW5zZm9ybShyZWFkT0dSKCIvVXNlcnMvc3VzdS9EZXNrdG9wL0hvbmdcIEtvbmcvU2VtZXN0ZXIyL0JpZ19EYXRhL2Fzc2lnbm1lbnRfZGF0YS9hczEvSW5kaXZpZHVhbHMxMjE2IiwgdG9TdHJpbmcoaSkpLCBDUlMoIitwcm9qPWxvbmdsYXQgK2RhdHVtPVdHUzg0IikpKQogIH0KfQoKc3VtbWFyeSh0bXBfSU5EW1sxXV0pCnN1bW1hcnkodG1wX0NDKQoKCnRtcF9DQyA8LSBnZW9tZXRyeShDQy5waikKdG1wX0xFIDwtIGdlb21ldHJ5KExFLnBqKQp0bXBfTENCRCA8LSBnZW9tZXRyeShMQ0JELnBqKQp0bXBfTE5DQkQgPC0gZ2VvbWV0cnkoTE5DQkQucGopCnRtcF9SQlJUIDwtIGdlb21ldHJ5KFJCUlQucGopCgpJTkQgPC0gYygpCmZvciAoaSBpbiAxOihsZW5ndGgobGF5ZXJfbGlzdCktMSkpewogIElORCA8LSBjKElORCwgdG1wX0lORFtbaV1dKQp9Cgp0bXBzIDwtIGxpc3QodG1wX0NDLCB0bXBfTEUsIHRtcF9MQ0JELCB0bXBfTE5DQkQsIHRtcF9SQlJULCBJTkQpCgpMaW5lX2xpc3QgPC0gbGlzdCgpCmZvciAoaSBpbiAxOjYpewogIGZvciAoaiBpbiAxOmxlbmd0aCh0bXBzW1tpXV0pKXsKICAgIExpbmVfbGlzdCA8LSBjKExpbmVfbGlzdCwgdG1wc1tbaV1dW2pdQGxpbmVzW1sxXV1ATGluZXMpCiAgfQp9CmBgYAoKCm1ha2UgbmV3X2lkCmBgYHtyfQpwanMgPC0gbGlzdChDQy5waiwgTEUucGosIExDQkQucGosIExOQ0JELnBqLCBSQlJULnBqKQpMaW5MU3MgPC0gbGlzdCgpCmZvciAoaSBpbiAxOjUpewogTGluTFNzIDwtIGMoTGluTFNzLCBzYXBwbHkocGpzW1tpXV1AbGluZXMsIGZ1bmN0aW9uKHgpIGxlbmd0aCh4QExpbmVzKSkpCn0KTGluTFNzIDwtIExpbkxTcyAlPiUgdW5saXN0KCkKCm5ld19pZCA8LSBzYXBwbHkoMTpsZW5ndGgoTGluTFNzKSwgZnVuY3Rpb24oeCkgcGFzdGUwKHgsICJfIiwgc2VxLmludChMaW5MU3NbW3hdXSkpKSAlPiUgCiAgdW5saXN0KCkKYGBgCgpgYGB7cn0KIyMgbWFrZSBhIG5ldyBkYXRhLmZyYW1lIChvbmx5IHJvdXRlX2lkKQpEQVQ9ZGF0YS5mcmFtZShtYXRyaXgocmVwKE5BLDEpLG5yb3c9MSkpWy0xLF0KZm9yIChpIGluIDE6NSl7CiAgZGYgPC0gZGF0YS5mcmFtZShyb3V0ZV9pZCA9IHBqc1tbaV1dQGRhdGEkVkFSX0lERU5UKQogIERBVCA8LSByYmluZChEQVQsIGRmKQp9CnJvd25hbWVzKERBVCkgPC0gbmV3X2lkCgpTTERGIDwtIG1hcHBseShmdW5jdGlvbih4LCB5KSBMaW5lcyh4LCBJRCA9IHkpLCB4ID0gTGluZV9saXN0LCB5ID0gbmV3X2lkKSAlPiUKICAjbGlzdCgpICU+JQogIFNwYXRpYWxMaW5lcygpICU+JSAKICBTcGF0aWFsTGluZXNEYXRhRnJhbWUoZGF0YSA9IERBVCkKYGBgCgoKbWFrZSBuZXcgbGluZXMgYW5kIExBIG1hcApgYGB7cn0KZGF0IDwtIGdlb2NvZGUoJ0xvcyBBbmdlbHMnKQoKbGVhZmxldCgpICU+JQogIHNldFZpZXcobG5nID0gZGF0Wydsb24nXSwgbGF0ID0gZGF0WydsYXQnXQksIHpvb20gPSAxMSkgJT4lCiAgYWRkUG9seWxpbmVzKGRhdGEgPSBTTERGLCBjb2xvciA9ICJibGFjayIsIG9wYWNpdHkgPSAxLCB3ZWlnaHQgPSAxKSAlPiUgCiAgYWRkQ2lyY2xlcyhkYXRhPVNPTC5wakBkYXRhLH5MT05HLCB+TEFULCBjb2xvciA9ICJyZWQiLCB3ZWlnaHQgPSAwLjMpICU+JQogIGFkZFRpbGVzKCkKYGBgCgoKIyMgUTMKCkZpcnN0IEkgbG9hZCB0aGUgZGF0YS4KYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkoaGlnaGNoYXJ0ZXIpCgp4IDwtIGdldFN5bWJvbHMoIkFVRC9KUFkiLCBzcmMgPSAib2FuZGEiLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQp5IDwtIGdldFN5bWJvbHMoIkdCUC9VU0QiLCBzcmMgPSAib2FuZGEiLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQpgYGAKCk5leHQgbWFrZSBCb2xsaW5nZXIncyBiYW5kcyBmb3IgZWFjaCBleGNoYW5nZSByYXRlLgpgYGB7cn0KeC5CQmFuZHMubGwgPC0gQkJhbmRzKHgpJGRuCnguQkJhbmRzLnVsIDwtIEJCYW5kcyh4KSR1cAp4LkJCYW5kcy5tIDwtIEJCYW5kcyh4KSRtYXZnCnkuQkJhbmRzLmxsIDwtIEJCYW5kcyh5KSRkbgp5LkJCYW5kcy51bCA8LSBCQmFuZHMoeSkkdXAKeS5CQmFuZHMubSA8LSBCQmFuZHMoeSkkbWF2ZwpgYGAKClRoZSBkcmF3aW5nIGNvZGUgaXMgYXMgZm9sbG93cy4KYGBge3J9CmhjIDwtIGhpZ2hjaGFydCh0eXBlPSJzdG9jayIpICU+JSAKICBoY190aXRsZSh0ZXh0PSJDaGFydGluZyBFeGNoYW5nZSBSYXRlcyIpICU+JSAKICBoY19zdWJ0aXRsZSh0ZXh0ID0gIkRhdGEgZXh0cmFjdGVkIHVzaW5nIHF1YW50bW9kIHBhY2thZ2UiKSAlPiUgCiAgaGNfeUF4aXNfbXVsdGlwbGVzKAogICAgbGlzdCh0b3AgPSAiMCUiLCBoZWlnaHQgPSAiNTAlIiwgb2Zmc2V0PTAsIG9wcG9zaXRlPVRSVUUpLAogICAgbGlzdCh0b3AgPSAiNTAlIiwgaGVpZ2h0ID0gIjUwJSIsIG9mZnNldD0wLCBvcHBvc2l0ZT1UUlVFKQogICklPiUKICBoY19hZGRfc2VyaWVzKHgsIGlkID0gImF1ZGpweSIsbmFtZSA9ImF1ZGpweSIsIHlBeGlzPTAsIGNvbG9yPSJibHVlIiwgbGluZVdpZHRoPTEuNSkgJT4lCiAgaGNfYWRkX3Nlcmllcyh4LkJCYW5kcy5sbCwgaWQgPSAiYXVkanB5LmxsIiwgbmFtZT0iYXVkanB5IExvd2VyIEJCYW5kcyIseUF4aXM9MCwKICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsZGFzaFN0eWxlPSdzaG9ydGRhc2gnLCBsaW5lV2lkdGg9MSkgJT4lCiAgaGNfYWRkX3Nlcmllcyh4LkJCYW5kcy51bCwgaWQgPSAiYXVkanB5LnVsIiwgbmFtZT0iYXVkanB5IFVwcGVyIEJCYW5kcyIseUF4aXM9MCwKICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsbGluZVdpZHRoPTEpICU+JQogIGhjX2FkZF9zZXJpZXMoeC5CQmFuZHMubSwgaWQgPSAiYXVkanB5Lm0iLG5hbWU9ImF1ZGpweSBCQmFuZHMgTUEiLCB5QXhpcz0wLAogICAgICAgICAgICAgICAgY29sb3I9InJlZCIsbGluZVdpZHRoPTEpICU+JQogIGhjX2FkZF9zZXJpZXMoeSwgaWQgPSAiZ2JwdXNkIixuYW1lPSJnYnB1c2QiLHlBeGlzPTEsIGNvbG9yPSJncmVlbiIsIGxpbmVXaWR0aD0xLjUpICU+JQogIGhjX2FkZF9zZXJpZXMoeS5CQmFuZHMubGwsIGlkID0gImdicHVzZC5sbCIsbmFtZT0iZ2JwdXNkIExvd2VyIEJCYW5kcyIsIHlBeGlzPTEsCiAgICAgICAgICAgICAgICBjb2xvcj0iYmxhY2siLGRhc2hTdHlsZT0nc2hvcnRkYXNoJyxsaW5lV2lkdGg9MSkgJT4lCiAgaGNfYWRkX3Nlcmllcyh5LkJCYW5kcy51bCwgaWQgPSAiZ2JwdXNkLnVsIixuYW1lPSJnYnB1c2QgVXBwZXIgQkJhbmRzIiwgeUF4aXM9MSwKICAgICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsbGluZVdpZHRoPTEpICU+JQogIGhjX2FkZF9zZXJpZXMoeS5CQmFuZHMubSwgaWQgPSAiZ2JwdXNkLm0iLG5hbWU9ImdicHVzZCBCQmFuZHMgTUEiLCB5QXhpcz0xLAogICAgICAgICAgICAgICAgY29sb3I9InJlZCIsbGluZVdpZHRoPTEpICU+JQogIGhjX2FkZF90aGVtZShoY190aGVtZV81MzgoKSkKCmhjCmBgYAoKCiMjIFE0CgpMb2FkIGxpYnJhcmllcyBhbmQgY2hlY2sgdGhlIHJhdyBkYXRhLiBBbmQgbWFrZSBmZmRmIGFmdGVyIGNvbnZlcnRpbmcgY2hhcmFjdGVyIGNvbHVtbnMgdG8gZmFjdG9yIGNvbHVtbnMgaW4gb3JpZ2luYWwgZGYuCmBgYHtyfQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKbGlicmFyeShmZmJhc2UpCmxpYnJhcnkoZmZiYXNlMikKbGlicmFyeShiaWdsbSkKbGlicmFyeShwUk9DKQpsaWJyYXJ5KGNocm9uKQoKdG1wIDwtIGZsaWdodHMKdG1wJGNhcnJpZXIgPC0gYXMuZmFjdG9yKHRtcCRjYXJyaWVyKQp0bXAkdGFpbG51bSA8LSBhcy5mYWN0b3IodG1wJHRhaWxudW0pCnRtcCRvcmlnaW4gPC0gYXMuZmFjdG9yKHRtcCRvcmlnaW4pCnRtcCRkZXN0IDwtIGFzLmZhY3Rvcih0bXAkZGVzdCkKCmZsaWdodGZmIDwtIGFzLmZmZGYodG1wKQpgYGAKCk5leHQgSSBtYWtlIG5ldyBjb2x1bW5zIGFzIGZvbGxvd3MKYGBge3J9CmZsaWdodGZmJERlbGF5IDwtIGZmaWZlbHNlKGZsaWdodGZmJGRlcF9kZWxheSA+IDAgfCBmbGlnaHRmZiRkZXBfZGVsYXkgPT0gMCAsIDEsMCkKZmxpZ2h0ZmYkRGVwSG91ciA8LSBmbGlnaHRmZiRob3VyCmZsaWdodGZmJENhciA8LSBmZmlmZWxzZShmbGlnaHRmZiRjYXJyaWVyICVpbiUgYXMuZmFjdG9yKGMoIkRMIiwiVVMiLCJESCIsIlVBIikpLCAxLCAwKQpmbGlnaHRmZiROaWdodCA8LSBmZmlmZWxzZShmbGlnaHRmZiRob3VyID4gMTggfCBmbGlnaHRmZiRob3VyIDwgNiwgMSwgMCkKZmxpZ2h0ZmYkV2Vla2VuZCA8LSBmZmlmZWxzZShkYXkub2Yud2Vlayhtb250aD1mbGlnaHRmZiRtb250aCwgZGF5PWZsaWdodGZmJGRheSwgeWVhcj1mbGlnaHRmZiR5ZWFyKSA9PSA2LCAxLCAwKQpgYGAKCkkgZXhjbHVkZSB0aGUgcm93cyB3aG9zZSBEZWxheSB2YWx1ZXMgYXJlIE5BIGFuZCByZW5hbWUgaXQgdG8gbG9naXRmZi4KQW5kIHRoZW4gSSBzcGxpdCB0aGUgZGF0YXNldCBpbnRvIHRyYWluIHNldCBhbmQgdGVzdCBzZXQuCmBgYHtyfQpsb2dpdGZmIDwtIGZsaWdodGZmWyFpcy5uYShmbGlnaHRmZiREZWxheSksXQoKaW5keCA8LSBmZigxOm5yb3cobG9naXRmZikpCnAgPC0gMC43CnRyYWluSW5keCA8LSBmZihpbmR4WzE6dHJ1bmMobGVuZ3RoKGluZHgpKnApXSkKdHJhaW5zZXQgPC0gbG9naXRmZlt0cmFpbkluZHgsXQp0ZXN0SW5keCA8LSBmZihpbmR4Wyh0cnVuYyhsZW5ndGgoaW5keCkqcCkrMSk6bGVuZ3RoKGluZHgpXSkKdGVzdHNldCA8LSBsb2dpdGZmW3Rlc3RJbmR4LF0KYGBgCgpMb2dpc3RpYyByZWdyZXNzaW9uIApgYGB7cn0KZml0IDwtIGJpZ2dsbS5mZmRmKERlbGF5fkRlcEhvdXIrQ2FyK05pZ2h0K1dlZWtlbmQsIGRhdGEgPSB0cmFpbnNldCwgZmFtaWx5PWJpbm9taWFsKCksIHNhbmR3aWNoPVRSVUUpCnN1bW1hcnkoZml0KQpgYGAKCnByZWRpY3QgYW5kIG1ha2UgY29uZnVzaW9ubWF0cml4IGluIHRyYWluX3NldApgYGB7cn0KdHJhaW5fcHJlZCA8LSBwcmVkaWN0KGZpdCwgbmV3ZGF0YSA9IHRyYWluc2V0LCB0eXBlPSJyZXNwb25zZSIpCnRyYWluX3ByZWQgPC0gaWZlbHNlKHRyYWluX3ByZWQ+MC41LCAxLDApCnRyYWluX2NvbmZ1c2lvbiA8LSB0YWJsZShhcy5pbnRlZ2VyKGFzLmRhdGEuZnJhbWUodHJhaW5zZXQpJERlbGF5KSwgYXMuaW50ZWdlcih0cmFpbl9wcmVkKSkKdHJhaW5fY29uZnVzaW9uIDwtIGFkZG1hcmdpbnModHJhaW5fY29uZnVzaW9uKQp0cmFpbl9jb25mdXNpb24KYGBgCgpwcmVkaWN0IGFuZCBtYWtlIGNvbmZ1c2lvbm1hdHJpeCBpbiB0ZXN0X3NldApgYGB7cn0KdGVzdF9wcmVkIDwtIHByZWRpY3QoZml0LCBuZXdkYXRhID0gdGVzdHNldCwgdHlwZT0icmVzcG9uc2UiKQp0ZXN0X3ByZWQgPC0gaWZlbHNlKHRlc3RfcHJlZD4wLjUsIDEsMCkKdGVzdF9jb25mdXNpb24gPC0gdGFibGUoYXMuaW50ZWdlcihhcy5kYXRhLmZyYW1lKHRlc3RzZXQpJERlbGF5KSwgYXMuaW50ZWdlcih0ZXN0X3ByZWQpKQp0ZXN0X2NvbmZ1c2lvbiA8LSBhZGRtYXJnaW5zKHRlc3RfY29uZnVzaW9uKQp0ZXN0X2NvbmZ1c2lvbgpgYGAKCkRyYXcgUk9DIGN1cnZlCmBgYHtyfQp0ZXN0X3ByZWQgPC0gcHJlZGljdChmaXQsIG5ld2RhdGEgPSB0ZXN0c2V0LCB0eXBlPSJyZXNwb25zZSIpCnJvYyA8LSByb2MoYXMuaW50ZWdlcihhcy5kYXRhLmZyYW1lKHRlc3RzZXQpJERlbGF5KSwgYXMubnVtZXJpYyh0ZXN0X3ByZWQpKQpwbG90KHJvYykKYGBgCgoKIyMgUTUKCkZpcnN0IEkgbG9hZCB0aGUgZGF0YS4gQW5kIGJlZm9yZSB1c2luZyBzcGFyayBJIGRlbGV0ZSB0aGUgaXJyZWxldmFudCBjb2x1bW5zLgpgYGB7cn0KbGlicmFyeShzcGFya2x5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKc2MgPC0gc3BhcmtfY29ubmVjdChtYXN0ZXIgPSAibG9jYWwiKQoKIyDlhYPjga5jc3bjgavllY/poYzjgYzjgYLjgovjgaPjgb3jgYTvvJ8g4oaSIFVuc3BlY2lmaWVk44GM5oCS44KJ44KM44Gm44KL44Gj44G944GE44CA4oaS44CAVW5zcGVjaWZpZWTjgpIw44Gr5aSJ44GI44KL44GL44CC4oaS5LuK5bqm44GvUEFTU0VOR0VSIFZFSElDS0XjgYzmgJLjgonjgozjgovjgIIKIyDopoHjgZnjgovjgatTdHJpbmfjgYzlhajpg6jjg4Djg6HjgaPjgb3jgYTjgILjgafjgoJ0aXRhbmlj44Gn44GvU3RyaW5n44KC5LiK5omL44GP5rih44Gb44Gm44KL44CC44Gq44Gc77yfCiMg5LqM44Gk44Gu5L6L44GL44KJ56m655m944Gv5Yil44Gr5ZWP6aGM44Gn44Gv44Gq44GE44GT44Go44GM44KP44GL44KL44CCCmRhdCA8LSByZWFkX2NzdigiL1VzZXJzL3N1c3UvRGVza3RvcC9Ib25nXCBLb25nL1NlbWVzdGVyMi9CaWdfRGF0YS9hc3NpZ25tZW50X2RhdGEvYXMxL05ZUERfTW90b3JfVmVoaWNsZV9Db2xsaXNpb25zLmNzdiIpCmRhdCA8LSBkYXRbLGMoIkJPUk9VR0giLCJMQVRJVFVERSIsIkxPTkdJVFVERSIsIlVOSVFVRSBLRVkiKV0KbnlwZF90YmwgPC0gY29weV90byhzYywgZGF0LCAibnlwZF90YmwiLG92ZXJ3cml0ZSA9IFRSVUUpCmBgYAoKUmVtb3ZlIHRoZSBvYnNlcnZhdGlvbnMgc2F0aXNmeWluZyB0aGUgY29uZGl0aW9uCmBgYHtyfQpueXBkX3RibCA8LSBueXBkX3RibCAlPiUKICBmaWx0ZXIoQk9ST1VHSCE9IiIsIWlzLm5hKExBVElUVURFKSwhaXMubmEoTE9OR0lUVURFKSxMQVRJVFVERSE9MCxMT05HSVRVREUhPTApCm55cGRfdGJsCmBgYAoKU3BsaXQgdGhpcyBkYXRhIGludG8gdHJhaW5zZXQgYW5kIHRlc3RzZXQuCmBgYHtyfQpwYXJ0aXRpb25zIDwtIG55cGRfdGJsICU+JQogIHNkZl9wYXJ0aXRpb24odHJhaW5pbmcgPSAwLjksIHRlc3QgPSAwLjEsIHNlZWQgPSAxMjMpCnRyYWluIDwtIHBhcnRpdGlvbnNbMV0kdHJhaW5pbmcKdGVzdCA8LSBwYXJ0aXRpb25zWzJdJHRlc3QKYGBgCgpVc2UgRGVjaXNpb24gdHJlZQpgYGB7cn0KZGVjaXNpb25fdHJlZSA8LSB0cmFpbiAlPiUKICBtbF9kZWNpc2lvbl90cmVlKHJlc3BvbnNlPSJCT1JPVUdIIiwgZmVhdHVyZXMgPSBjKCJMQVRJVFVERSIsIkxPTkdJVFVERSIpLCBtYXguYmlucyA9IDIwMEwsIG1heC5kZXB0aCA9IDEwTCwgc2VlZD0xMjNMKSAlPiUKYGBgCgpQcmVkaWN0aW9uCmBgYHtyfQpwcmVkIDwtIHNkZl9wcmVkaWN0KGRlY2lzaW9uX3RyZWUsIHRlc3QpICU+JQogIGNvbGxlY3QKCnRhYmxlKHByZWQkQk9ST1VHSCwgcHJlZCRwcmVkaWN0aW9uKQpgYGAKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK